#include <iostream>
#include <vector>
#include <array>
#include <cstddef>
#include <cmath>

#include "clp/clp.hpp"
#include "util/util.hpp"

using namespace util::literals;

constexpr size_t board_size = 9;
constexpr size_t board_square_size = (int) std::sqrt(board_size);

using board_impl = std::array<clp::var<std::byte>, board_size * board_size>;
struct board : board_impl {
    constexpr board() : board_impl{} {
        size_t id = 0;
        for (auto &c : *this) {
            c.id = id++;
            c.val = 1_b;
            c.val_known = true;
        }
    }
};

std::ostream & operator<<(std::ostream &os, const board &b) {
    const auto bold = [](auto i) { return i % board_square_size == 0; };
    const auto horizontal = [&os, &bold](auto row) {
        const auto edge = [&bold](auto row, std::array<const char *, 4> c) { return (row == 0 ? c[0] : (row == board_size ? c[1] : (bold(row) ? c[2] : c[3]))); };
        os << edge(row, {"┏", "┗", "┣", "┠"});
        for (size_t k = 1; k <= 4 * board_size - 1; ++k) {
            os << (k % 4 == 0 ? (row == 0 ? (bold(4 * k) ? "┳" : "┯") :
                                 (row == board_size ? (bold(4 * k) ? "┻" : "┷") :
                                  (bold(row) && bold(4 * k) ? "╋" :
                                   (bold(4 * k) ? "╂" : (bold(row) ? "┿" : "┼"))))) :
                   (bold(row) ? "━" : "─"));
        }
        os << edge(row, {"┓", "┛", "┫", "┨"});
        os << '\n';
    };
    const auto vertical = [&os, &bold](auto col) {
        os << (bold(col) ? "┃" : "│");
    };
    horizontal(0);
    for (size_t row = 1; row <= board_size; ++row) {
        vertical(0);
        for (size_t col = 1; col <= board_size; ++col) {
            auto v = b[(row - 1) * board_size + (col - 1)];
            if (v.val_known) {
                os << ' ' << v.val << ' ';
            } else {
                os << "   ";
            }
            vertical(col);
        }
        os << '\n';
        horizontal(row);
    }
    return os;
}

int main() {
    board b{};
    std::cout << b;
    return 0;
}
